<?php

/**
 * yaf 框架报错类调用
 *  默认错误会调用这个Controller 中 ErrorAction
 */
class ErrorController extends Yaf_Controller_Abstract
{

    private $_config;

    public function init()
    {
        Yaf_Dispatcher::getInstance()->disableView();
        $this->_config = Yaf_Application::app()->getConfig();
    }

    /**
     * [具体错误处理]
     * @param Exception $exception [description]
     * @return [type]               [description]
     */
    public function errorAction(Exception $exception)
    {
        if ($this->_config->application->debug) {
            //禁止输出视图内容
            switch ($exception->getCode()) {
                case YAF_ERR_AUTOLOAD_FAILED:
                case YAF_ERR_NOTFOUND_MODULE:
                case YAF_ERR_NOTFOUND_CONTROLLER:
                case YAF_ERR_NOTFOUND_ACTION:
                case YAF_ERR_NOTFOUND_VIEW:
                    if (strpos($this->getRequest()->getRequestUri(), '.css') !== false ||
                        strpos($this->getRequest()->getRequestUri(), '.jpg') !== false ||
                        strpos($this->getRequest()->getRequestUri(), '.js') !== false ||
                        strpos($this->getRequest()->getRequestUri(), '.png') !== false ||
                        strpos($this->getRequest()->getRequestUri(), '.ico') !== false ||
                        strpos($this->getRequest()->getRequestUri(), '.gif') !== false
                    ) {
                        #header('HTTP/1.1 404 Not Found');
                        #json("404 Not Found");
                        $result = [
                            'ret' => 1,
                            'msg' => '404 Not Found',
                        ];
                    } else {
                        $result = [
                            'ret' => 2,
                            'msg' => $exception->getMessage(),
                        ];
                    }
                    break;
                case 100:
                case 400:
                case 403:
                    $result = [
                        'ret' => $exception->getCode(),
                        'msg' => $exception->getMessage(),
                    ];
                    break;
                case 401:
                    redirect('/main/login');
                    break;
                case 402:
                    redirect('/public/adminlogin');
                    break;
                default:
                    //记录错误日志
                    Log::out('error', 'I', $exception->getMessage() . ' IN FILE ' . $exception->getFile() . ' ON LINE ' . $exception->getLine());
                    $result = [
                        'ret' => 500,
                        'msg' => $exception->getMessage(),
                    ];
            }
            #debug模式，添加错误代码、文件、及行号
            if (!in_array($exception->getCode(), [100, 400, 401, 402])) {
                $result['data'] = [
                    'code' => $exception->getCode(),
                    'file' => $exception->getFile(),
                    'line' => $exception->getLine(),
                ];
            }
            if (NULL !== $exception->getPrevious()) {
                $result['data']['file'] = $exception->getPrevious()->getFile();
                $result['data']['line'] = $exception->getPrevious()->getLine();
                $result['data']['msg']  = $exception->getPrevious()->getMessage();
            }
            json($result);
        } else {
            switch ($exception->getCode()) {
                case YAF_ERR_AUTOLOAD_FAILED:
                case YAF_ERR_NOTFOUND_MODULE:
                case YAF_ERR_NOTFOUND_CONTROLLER:
                case YAF_ERR_NOTFOUND_ACTION:
                case YAF_ERR_NOTFOUND_VIEW:
                case 404:
                    #header('HTTP/1.1 404 Not Found');
                    //记录日志
                    Log::out('error', 'I', $exception->getMessage() . ' IN FILE ' . $exception->getFile());
                    #$this->_view->assign('type', 'err404');
                    $result = [
                        'ret' => 404,
                        'msg' => '404 Not Found',
                    ];
                    $this->_view->assign('dataset', $result);
                    $this->_view->display('error/404.html');
                    break;
                case 100:
                    $result = [
                        'ret' => 100,
                        'msg' => $exception->getMessage(),
                    ];
                    json($result);
                    break;
                case 401:
                    redirect('/main/login');
                    break;
                case 402:
                    $result = [
                        'ret' => 402,
                        'msg' => $exception->getMessage(),
                    ];
                    redirect('/public/adminlogin');
                    break;
                case 403:
                    $result = [
                        'ret' => 403,
                        'msg' => $exception->getMessage(),
                    ];
                    json($result);
                    break;
                default:
                    #header('HTTP/1.1 500 Internal Server Error');
                    //记录文件错误日志
                    Log::out('error', 'I', $exception->getMessage() . ' IN FILE ' . $exception->getFile() . ' ON LINE ' . $exception->getLine());
                    $result = [
                        'ret' => 500,
                        'msg' => $exception->getMessage(),
                    ];
                    $this->_view->assign('dataset', $result);
                    $this->_view->display('error/error.html');
                    break;
            }
        }
    }

    public function renderSourceCode($file, $errorLine, $maxLines)
    {

        $errorLine--; // adjust line number to 0-based from 1-based

        if ($errorLine < 0 || ($lines = @file($file)) === false || ($lineCount = count($lines)) <= $errorLine)

            return '';


        $halfLines = (int)($maxLines / 2);

        $beginLine = $errorLine - $halfLines > 0 ? $errorLine - $halfLines : 0;

        $endLine = $errorLine + $halfLines < $lineCount ? $errorLine + $halfLines : $lineCount - 1;

        $lineNumberWidth = strlen($endLine + 1);


        $output = '';

        for ($i = $beginLine; $i <= $endLine; ++$i) {

            $isErrorLine = $i === $errorLine;

            $oneline = str_replace(['<', '>'], ['&lt', '&gt'], $lines[$i]);

            $code = sprintf("<span class=\"ln" . ($isErrorLine ? ' error-ln' : '') . "\">%0{$lineNumberWidth}d</span> %s", $i + 1, $oneline);

            if (!$isErrorLine)

                $output .= $code;

            else

                $output .= '<span class="errorflag">' . $code . '</span>';

        }

        return '<div class="code"><pre>' . $output . '</pre></div>';

    }

    public function isCoreCode($trace)

    {

        if (isset($trace['file'])) {

            $systemPath = realpath(dirname(__FILE__) . '/..');

            return $trace['file'] === 'unknown' || strpos(realpath($trace['file']), $systemPath . DIRECTORY_SEPARATOR) === 0;

        }

        return false;

    }

    public function argumentsToString($args)

    {

        $count = 0;


        $isAssoc = $args !== array_values($args);


        foreach ($args as $key => $value) {

            $count++;

            if ($count >= 5) {

                if ($count > 5)

                    unset($args[$key]);

                else

                    $args[$key] = '...';

                continue;

            }


            if (is_object($value))

                $args[$key] = get_class($value);

            elseif (is_bool($value))

                $args[$key] = $value ? 'true' : 'false';

            elseif (is_string($value)) {

                if (strlen($value) > 64)

                    $args[$key] = '"' . substr($value, 0, 64) . '..."';

                else

                    $args[$key] = '"' . $value . '"';

            } elseif (is_array($value))

                $args[$key] = 'array(' . $this->argumentsToString($value) . ')';

            elseif ($value === null)

                $args[$key] = 'null';

            elseif (is_resource($value))

                $args[$key] = 'resource';


            if (is_string($key)) {

                $args[$key] = '"' . $key . '" => ' . $args[$key];

            } elseif ($isAssoc) {

                $args[$key] = $key . ' => ' . $args[$key];

            }

        }

        $out = implode(", ", $args);


        return $out;

    }

}

